package interceptor;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import common.VerifyToken;
import dao.mysql.AccountMySQLDao;
import entity.Account;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

public class AuthInterceptor implements HandlerInterceptor {
    private Object getDaoObject(String beanName) {
        return new ClassPathXmlApplicationContext("applicationContext.xml").getBean(beanName);
    }

    private AccountMySQLDao accountHelper = (AccountMySQLDao) getDaoObject("AccountMySQLDao");

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object object) throws Exception {
        String token = request.getHeader("Authorization");
        if (!(object instanceof HandlerMethod)) return true;
        HandlerMethod handlerMethod = (HandlerMethod) object;
        Method method = handlerMethod.getMethod();
        if (method.isAnnotationPresent(VerifyToken.class)) {
            VerifyToken loginToken = method.getAnnotation(VerifyToken.class);
            if (loginToken.required()) {
                if (token == null) throw new Exception("Please login first.");
                String username;
                try {
                    username = JWT.decode(token).getAudience().get(0);
                } catch (JWTDecodeException e) {
                    throw new RuntimeException("Incorrect token.");
                }
                Account a = accountHelper.queryAsEntity(username);
                if (a == null) throw new RuntimeException("Account does not exist.");
                JWTVerifier jwtVerifier =
                        JWT.require(Algorithm.HMAC256(a.getD_password())).build();
                try {
                    jwtVerifier.verify(token);
                } catch (JWTVerificationException e) {
                    throw new RuntimeException("Token invalid. Please login again.");
                }
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object object,
                           ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object object,
                                Exception e) throws Exception {
    }
}
